home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 4 / The 640 Meg Shareware Studio CD-ROM Volume IV (Data Express)(1994).ISO / clang / 121_01.zip / TEL.C < prev    next >
Text File  |  1993-06-01  |  23KB  |  1,118 lines

  1. /*
  2. HEADER: CUG 121.??;
  3.  
  4.     TITLE:    tel - dumb terminal + file xfer;
  5.     VERSION:    1.0;
  6.     DATE:    01/06/86;
  7.     DESCRIPTION: "Tel is a considerably modified version of Telnet v2.3, as
  8.         distributed with v1.46 of the BDS C compiler.  The following
  9.         features have been added: multiple files may be transmitted or
  10.         received by one command, directories may be listed, and the
  11.         quit command hangs up a hayes smartmodem.  To accommodate
  12.         these changes, some of the command names have been changed.
  13.         This program uses a modem to emulate a dumb terminal.
  14.         Incoming data may be buffered in memory and written to disk, 
  15.         data may be transmitted from disk to the modem, or files may
  16.         be formally transferred in a "checksum" mode with automatic
  17.         handshaking and buffering.";
  18.     KEYWORDS:    terminal, modem, emulate, file transfer;
  19.     SYSTEM:    CP/M;
  20.     FILENAME:    TEL.C;
  21.     WARNINGS:    "Requires local.c and files.c for link.
  22.         The checksum file transfer does not follow the XMODEM
  23.         protocol.
  24.         Variable baud rate support is present, but commented out
  25.         (hardware-specific coding would be required to implement it).
  26.         Tel assumes that the CP/M console is much faster than the
  27.         modem (e.g. a 1200+ baud console with a 300 baud modem).";
  28.     SEE-ALSO:    CALL.C, TELNET.C, TL370.C;
  29.     AUTHORS:    Leor Zolman, Leo Kenen, Cal Thixton, Mike W. Meyer;
  30.     COMPILERS:    BDS-C 1.50;
  31. */
  32.  
  33. #include <bdscio.h>    /* System, h'ware constants            */
  34. #include <hardware.h>
  35.  
  36. #ifdef MULL    /* muellers version if MULL is defined.            */
  37.  
  38. #define TITLE "Mulltel version 1.5    12/3/80 tj"
  39. #define    INITB    3    /* 1200 baud initially                */
  40. #define    SSPECIAL '\\'    /* escape character initially            */
  41.  
  42. #else
  43.  
  44. #define TITLE "Telnet version 3.0-Intersystems    10/25/80 (mwm)\n"
  45. #define    SSPECIAL 29    /* Initial escape character ^]            */
  46. #define    INITB    5    /* 4800 baud initially. See setbaud()        */
  47.  
  48. #endif
  49.  
  50. #define    SELDSK    14    /* change logged in disk    */
  51. #define    DIRFRST    17    /* search for first occurance of a file */
  52. #define    DIRNEXT    18    /* search for next occurance of a file */
  53. #define    CURRDSK    25    /* return currently logged in disk    */
  54. #define    maxfiles    64    /* maximun # of file to send as once */
  55.  
  56. /*
  57.     The following #defines need not be changed:
  58. */
  59.  
  60. #define    ACK    0x06    /* Ascii ACK for handshaking    */
  61. #define    NAK    0x15
  62. #define    EOT    0x04    /* End of transmission        */
  63. #define    ETX    0x03    /* Abort Transmission        */
  64. #define    STX    0x02    /* Beginning of next filename to send    */
  65. #define    NUL    0x0    /* end of file name    */
  66. #define PHA    0xfd    /* for phase checking    */
  67. #define CR    0x0d    /* carriage return    */
  68. #define LF    0x0a    /* line feed        */
  69. #define NL    '\n'    /* god knows, compiler dependent!    */
  70.  
  71. /*
  72.     File Control Block structure
  73. */
  74.  
  75. struct    FCB    {
  76.     char    entry,        /* entry type. assumed 0    */
  77.         name[8],    /* file name    */
  78.         type[3],    /* file type    */
  79.         extent,        /* which entention is this one?    */
  80.         na,naa,        /* not used (??)    */
  81.         count,        /* record count    */
  82.         map[16],    /* disk allocation map    */
  83.         next;        /* next record to read    */
  84.     };
  85.  
  86. /*
  87.     External variable declarations:
  88. */
  89.  
  90. char    SPECIAL;    /* current SPECIAL or escape character        */
  91. char    rflag;        /* receiving file open flag            */
  92. char    tflag;        /* transmitting file open flag            */
  93. char    chflag;        /* checksumming enabled flag            */
  94. char    cflag;        /* text-collection enabled flag         */
  95. char    pflag;        /* pausing flag                 */
  96. char    spflag;        /* stripping parity bit flag            */
  97. char    nflag;        /* recognizing nulls flag            */
  98. char    fflag;        /* true if changing CR-LF's into
  99.                 just CR when transmitting        */
  100. char    lastc;        /* last char transmitted            */
  101. char    dodflag;    /* true if displaying outging data        */
  102. char    didflag;    /* true if displaying incoming data        */
  103. char    hdflag;        /* true if effectively working in half-duplex     */
  104. char    hd_sav;        /* save flag when transmitting or receiving     */
  105. char    abortf;        /* true when file I/O aborted            */
  106. char    rbuf[BUFSIZ];     /* file I/O buffer for incoming data file     */
  107. char    tbuf[SECSIZ];     /* sector buffer for file being transmitted    */
  108. char    tmp[20];    /* tempory holding place for file name        */
  109. char    rname[20];     /* name of receiving file            */
  110. char    tname[20];     /* name of transmitting file            */
  111. int    rfd, tfd;    /* file descriptors                */
  112. char    *cptr;        /* pointer to free space in buf         */
  113. unsigned free;        /* number of bytes free in buf            */
  114. int     bcount;        /* counts bytes in current block when checksumming */
  115. int     scount;        /* Number of sectors sent/received        */
  116. int     checksum;    /* the checksum value itself            */
  117. char    timoutf;    /* 1 if time-out happens while waiting for modem data*/
  118. char    *i;        /* odd-job char pointer             */
  119. int     dod_sav, did_sav;    /* scratch variables            */
  120. unsigned bufspace;    /* # of bytes available for collection buffer in ram */
  121. char    toupper();    /* This makes for better code             */
  122. char    fcb[34];    /* file control block                */
  123. struct {            /* so i can't use initializers        */
  124.     char    rate[5],    /* readable baud rate            */
  125.         hex;
  126.     } bauds [7];
  127. char    current;        /* current baud rate being used        */
  128. char    files[maxfiles][17];    /* files to send             */
  129. char    leftover;    /* number of file to send             */
  130. char    thisdisk;    /* currently logged in disk            */
  131. char    *buf;        /* text collection pointer; will
  132.                 point to the location just after itself */
  133.  
  134. /*
  135.     place for main.c
  136. */
  137.  
  138. main()
  139. {
  140.     char    c, c2;
  141.     int n;
  142.  
  143.     init();
  144.  
  145.     while(1) {
  146.         if (abortf) {
  147.             if (rflag) 
  148.                 rclose();
  149.             if (tflag) 
  150.                 tabort();
  151.             reset();
  152.             abortf = 0;
  153.             }
  154.         if (tflag && xmit()) {
  155.             printf("\nTransmission complete.\n");
  156.             close(tfd);
  157.             reset();
  158.             }
  159.         if (abortf) 
  160.             continue;
  161.         if (miready()) {
  162.             c = c2 = getmod();
  163.             if (spflag)
  164.                 c &= 0x7f;
  165.             if (tflag && (c == ETX)) {
  166.                 printf("Receiver has aborted;\n");
  167.                 abortf = 1;
  168.                 continue;
  169.                 }
  170.             if (didflag && (c || nflag) && (c != CPMEOF))
  171.                 display(c);
  172.             if (cflag && !pflag) {
  173.                 if (c || nflag)
  174.                     if (!free) {
  175.                          printf("**BUFFER FULL**\007\007");
  176.                          rdump(0);
  177.                         }
  178.                     else {
  179.                         *cptr++ = c;
  180.                         free--;
  181.                         }
  182.                 if (chflag) {
  183.                     checksum += c2;
  184.                     bcount++;
  185.                     if (bcount == SECSIZ) {
  186.                         bcount = 0;
  187.                         outmod(checksum >> 8);
  188.                         outmod(checksum);
  189.                         checksum = 0;
  190.                         c = getmod();
  191.                         if(c == STX) {
  192.                             getname(tmp);
  193.                             rdump(0);
  194.                             rclose();
  195.                             scount=0;
  196.                             strcpy(rname,tmp);
  197.                             if(opento()) {
  198.                                 outmod(ETX);
  199.                                 abortf=1;
  200.                                 }
  201.                             outmod(PHA);
  202.                             }
  203.                         else if (c == EOT) {
  204.                             rdump(0);
  205.                             rclose();
  206.                             reset();
  207.                             printf("\n%s received OK\n",rname);
  208.                             }
  209.                         else if (c == ACK) {
  210.                             if (cptr > buf+1000) 
  211.                                 rdump(0);
  212.                             if (!didflag) 
  213.                                 printf("-%d",++scount);
  214.                             outmod(PHA);
  215.                             }
  216.                         else  {
  217.                             cptr -= SECSIZ;
  218.                             free += SECSIZ;
  219.                             printf("\nChecksum error. Retrying <%d>\n",scount+1);
  220.                             outmod(PHA);
  221.                             timoutf = 0;
  222.                             }
  223.                         }
  224.                     }
  225.                 }
  226.             }
  227.         if (kbready()) {
  228.             c = getch();
  229.             if (c != SPECIAL) {
  230.                 if (pflag || (!tflag && !(rflag && chflag))) {
  231.                     outmod(c);
  232.                     if (dodflag) 
  233.                         display(c);
  234.                     }
  235.                 }
  236.             else special();
  237.             }
  238.     }
  239. }
  240.  
  241.  
  242. /*
  243.     place for special.c
  244. */
  245.  
  246. /*
  247.     Handle special Telnet command:
  248. */
  249.  
  250. special()
  251. {
  252.     char c;
  253.     int nn,n;
  254.  
  255.     printf("\n?: ");
  256.     if ( (c = getchar()) != NL) printf("...");
  257.     if(c==SPECIAL) {
  258.         outmod(SPECIAL);
  259.         printf("Current Escape 0x%02x sent", SPECIAL) ;
  260.         }
  261.     else switch (toupper(c)) {
  262.         case 'E' :    
  263.             printf("Current Escape Character: 0x%02x\n",SPECIAL);
  264.             printf("Enter New Escape Character: ");
  265.             SPECIAL=getchar();
  266.             putchar(NL);
  267.             break;
  268.  
  269.         case '7':
  270.             spflag = ask("Strip parity");
  271.             break;
  272.  
  273.         case 'B':
  274.             dobauds();
  275.             break;
  276.  
  277.         case 'N':
  278.             nflag = ask("Recognize incoming nulls");
  279.             break;
  280.  
  281.         case 'F':
  282.             fflag = ask("Transmit CR-LF pairs as CR only");
  283.             break;
  284.  
  285.         case 'H':
  286.             if (rflag || tflag)  { 
  287.                 printf("Must abort transfer first\n");
  288.                 break;
  289.                 }
  290.             hd_sav = hdflag = ask ("Half Duplex");
  291.             reset();
  292.             break;
  293.  
  294.         case 'Z':
  295.             puts(CLEARS) ;
  296.             break;
  297.  
  298.         case 'P':
  299.             if (pflag) 
  300.                 printf("Already pausing");
  301.             else if (!(tflag || rflag))
  302.                 printf("Not transmitting or receiving");
  303.             else {
  304.                 pflag = 1;
  305.                 dod_sav = dodflag;
  306.                 did_sav = didflag;
  307.                 dodflag = !hdflag;
  308.                 didflag = 1;
  309.                 printf("Pausing from %s", tflag ?
  310.             "transmission" : "collection");
  311.                 }
  312.             putchar(NL);
  313.             break;
  314.  
  315.         case 'R':
  316.             if (!pflag) 
  317.                 printf("Not pausing");
  318.             else {
  319.                 pflag = 0;
  320.                 dodflag = dod_sav;
  321.                 didflag = did_sav;
  322.                 printf("%s now enabled again.", tflag ?
  323.                 "transmission" : "collection");
  324.             }
  325.             putchar(NL);
  326.             break;
  327.  
  328.         case 'K':
  329.             printf("Text buffer: ZAPPED!");
  330.             free = bufspace;
  331.             cptr = buf;
  332.             putchar(NL);
  333.             break;
  334.  
  335.         case 'V':
  336.             if (rflag) {
  337.                 putchar(NL);
  338.                 i = buf;
  339.                 while (i < cptr && !kbready())
  340.                     putchar(*i++);
  341.                 if(i<cptr)
  342.                     getchar();
  343.                 printf("\n%u bytes free",free);
  344.                 }
  345.             else 
  346.                 printf("No receiving file open");
  347.             putchar(NL);
  348.             break;
  349.  
  350.  
  351.         case 'D':
  352.             if (rflag)
  353.                 rdump(1);
  354.             else 
  355.                 printf("No output file");
  356.             putchar(NL);
  357.             break;
  358.  
  359.         case 'C':
  360.             if (rflag) 
  361.                 rclose();
  362.             else 
  363.                 printf("No output file");
  364.             putchar(NL);
  365.             break;
  366.  
  367.  
  368.         case 'Q': hangup() ;    /* hangup the modem */
  369.             
  370.         case 'X':
  371.             printf("Quit\n");
  372.             if (tflag) tabort();
  373.             if (rflag) rclose();
  374.             exit();
  375.  
  376.         case 'A':
  377.             if (tflag || rflag) {
  378.                   if (chflag) outmod(ETX);
  379.                 abortf = 1;
  380.                  break;
  381.                 }
  382.             printf("No transfer to abort.\n");
  383.             putchar(NL);
  384.             break;
  385.  
  386.         case 'O':
  387.             if (rflag) 
  388.                 rclose();
  389.             if (tflag) 
  390.                 tabort();
  391.             rflag = 1;
  392.             if (!askstuff()) {
  393.                 reset();
  394.                 return;
  395.                 }
  396.             cptr = buf;
  397.             free = bufspace;
  398.             rflag = cflag = 1;
  399.             scount = pflag = checksum = bcount = 0;
  400.             if (chflag) {
  401.                 printf("Trying to link...");
  402.                 do {
  403.                     c = getmod();
  404.                     if (abortf) {
  405.                         printf("aborting...\n");
  406.                         reset();
  407.                         return;
  408.                         }
  409.                     timoutf = 0;
  410.                 } while (c & 0x7f);
  411.                 printf("linked.\n");
  412.                 outmod(0);
  413.                 if(getmod() != STX) {
  414.                     printf("STX ERROR\n");
  415.                     reset();
  416.                     return;
  417.                     }
  418.                 getname(rname);
  419.                 if(opento()) {
  420.                     outmod(ETX);
  421.                     abortf=1;
  422.                     }
  423.                 outmod(PHA);
  424.                 }
  425.             break;
  426.  
  427.         case 'T':
  428.             printf("Transmit\n");
  429.             if (tflag) 
  430.                 tabort();
  431.             if (rflag) 
  432.                 rclose();
  433.             printf("\nEnter file names to send:\n");
  434.             leftover=0;
  435.             while(1) {
  436.                 ++leftover;
  437.                 printf("%d) File name: ",leftover);
  438.                 gets(files[leftover-1]);
  439.                 n=leftover;
  440.                 if(nameok())    /* return 1 too many or end */
  441.                     break;
  442.                 for(nn=n;nn<=leftover;nn++) 
  443.                     printf("File %d: %s\n",nn,files[nn-1]);
  444.                 }
  445.             printf("%d Files to send\n",--leftover);
  446.             if (!leftover || !askstuff()) {
  447.                 reset();
  448.                 break; 
  449.                 }
  450.             strcpy(tname,files[leftover-1]);
  451.             tflag = 1;
  452.             if(leftover && ((tfd=open(tname,0))==ERROR)) {
  453.                 printf("Fatal error: Cannot open %s\n",tname);
  454.                 reset();
  455.                 abortf=1;
  456.                 break;
  457.                 }
  458.             scount = pflag = checksum = bcount = 0;
  459.             if (read(tfd,tbuf,1) <=0) {
  460.                 printf("Read error from %s\n",tname);
  461.                 reset();
  462.                 abortf = 1;
  463.                 break;
  464.                 }
  465.             if (chflag) {
  466.                 printf("Trying to link...");
  467.                 while (1) {
  468.                   outmod(0);
  469.                   for (n=0; n<5000; n++)
  470.                     if (miready()) {
  471.                         if(!(getmod()&0x7f)){
  472.                             printf("linked.\n");
  473.                             outmod(STX);
  474.                             sendname(tname);
  475.                             printf("\nSending %d: %s\n",leftover,tname);
  476.                             if(getmod()!=PHA) {
  477.                                 printf("ERROR\n");
  478.                                 abortf=1;
  479.                                 }
  480.                             return;
  481.                             }
  482.                         }
  483.                     else
  484.                         if (kbabort()) {
  485.                             printf("aborting.\n");
  486.                             return;
  487.                             }
  488.                     }
  489.                 }
  490.             break;
  491.  
  492.         case 'S':
  493.             dostat();
  494.             break;
  495.  
  496.         case 'L':
  497.             if(rflag || tflag) {
  498.                 printf("Cannot list disk while %s data\n",
  499.                     (rflag)?"receiving":"transmitting");
  500.                 break;
  501.                 }
  502.             dir();
  503.             break;
  504.  
  505.         case 'G':
  506.             if(rflag || tflag) {
  507.                 printf("Cannot change disk while %s data\n",
  508.                     (rflag)?"receiving":"transmitting");
  509.                 break;
  510.                 }
  511.             printf("Newly logged-in Disk: %c:\n",togdisk());
  512.             break;
  513.  
  514.         default:
  515.             prcoms();
  516.     }
  517. }
  518.  
  519.  
  520.  
  521.  
  522. /*
  523.     Print out legal Telnet commands:
  524. */
  525.  
  526. prcoms()
  527. {
  528.     puts(CLEARS) ;
  529.     printf("BDS Telnet commands are:\n");
  530.     printf("?: This listing\n");
  531.     printf("0x%02x: send 0x%02x\n",SPECIAL,SPECIAL);
  532.     printf("7: Select policy regarding Parity bits\n");
  533.     printf("a: Abort transfer of file\n");
  534.     printf("b: Select baud rate\n");
  535.     printf("c: Close input file (after dumping buffer)\n");
  536.     printf("d: Dump (append) text buffer to output file\n");
  537.     printf("e: Change ESCAPE Character\n");
  538.     printf("f: Select whether to transmit CR-LF as just CR\n");
  539.     printf("g: Go (login) to other disk\n");
  540.     printf("h: Set Half/full duplex mode\n");
  541.     printf("k: Kill (erase) contents of input buffer\n");
  542.     printf("l: List files on disks\n");
  543.     printf("n: Accept or ignore Nulls\n");
  544.     printf("o: Open input file, start collection\n");
  545.     printf("p: Pause (suspend collection or transmission)\n");
  546.     printf("q: Dump & close input file (if open) and Quit to CP/M\n");
  547.     printf("r: Resume after pausing\n");
  548.     printf("s: Display Status\n");
  549.     printf("t: Transmit a file\n");
  550.     printf("v: View contents of input buffer\n");
  551.     printf("x: eXit to CP/M, don't hangup the modem\n") ;
  552.     printf("z: Clear screen\n");
  553. }
  554.  
  555. /*
  556.     Print opening message and initialize program:
  557. */
  558.  
  559. init()
  560. {
  561.     printf(TITLE);
  562.  
  563.     _allocp = NULL;      /* initialize allocation pointer */
  564.  
  565.     hdflag = hd_sav = lastc = timoutf = cflag = 0;
  566.     nflag = pflag = abortf = fflag = 0;
  567.     spflag=1;
  568.     SPECIAL=SSPECIAL;    /* initial escape character */
  569.  
  570.     buf = &buf + 1;
  571.     bufspace = buf + 500 - topofmem();/* compute space available */
  572.     bufspace = -bufspace;          /* for text collection buf */
  573.  
  574.     reset();
  575. /*    initbaud();
  576.     setbaud(current=INITB);    /* defualt baud rate: 4800     */
  577. leave this stuff out, for now... */
  578. }
  579.  
  580. /*
  581.     hangup a hayes smartmodem
  582. */
  583.  
  584. hangup() {
  585.  
  586.     sleep(20) ;        /* a nice long wait */
  587.     hayesput("...") ;    /* get it's attention */
  588.     hayesput("AT H\r") ;    /* tell it to hang up */
  589.     }            /* and we is through */
  590. /*
  591.     set baud rates
  592. */
  593.  
  594. setbaud(r)
  595. char    r;
  596. {
  597. /*
  598.     outp(CTCPORT,SETBAUD);        /* set baud rate    */
  599.     outp(CTCPORT,bauds[r].hex);
  600. are you kidding */
  601. }
  602.  
  603. initbaud()
  604. {
  605.     strcpy(bauds[0].rate,"110");    bauds[0].hex=0x57;
  606.     strcpy(bauds[1].rate,"300");    bauds[1].hex=0x20;
  607.     strcpy(bauds[2].rate,"600");    bauds[2].hex=0x10;
  608.     strcpy(bauds[3].rate,"1200");    bauds[3].hex=0x8;
  609.     strcpy(bauds[4].rate,"2400");    bauds[4].hex=0x4;
  610.     strcpy(bauds[5].rate,"4800");    bauds[5].hex=0x2;
  611.     strcpy(bauds[6].rate,"9600");    bauds[6].hex=0x1;
  612. }
  613.  
  614.  
  615. dobauds()
  616. {
  617.     char    n;
  618.  
  619.     puts(CLEARS) ;
  620.     printf("Current Baud rate is %s\n\n",
  621.         bauds[current].rate);
  622.     for(n=0; n<7; n++)
  623.           printf("%c: %s\n",n+0x41,bauds[n].rate);
  624.     printf("\nWhich rate? ");
  625.     n=toupper(getchar())-0x41;
  626.     if(n>=0 && n<7)
  627.         setbaud(current=n);
  628.     putchar(NL);
  629. }
  630.  
  631. /*
  632.     rest of tel.c stuff
  633. */
  634.  
  635.  
  636. /*
  637.     Get all the info pertinent to a file transfer; i.e,
  638.     whether or not the file is text (and needs parity
  639.     stripped, nulls ignored, echoing to console, etc.),
  640.     whether or not checksumming and handshaking are
  641.     required (they always go together), and make sure
  642.     the user is in full duplex mode.
  643. */
  644.  
  645. askstuff()
  646. {
  647.     chflag = ask("Handshaking & checksumming:");
  648.     if (!chflag && ask("Is this a text file")) {
  649.         nflag = 0;
  650.         spflag = didflag = 1;
  651.         dodflag = !hdflag;
  652.         }    
  653.     else {    
  654.         spflag = didflag = dodflag = 0;
  655.         nflag = 1;
  656.         }
  657.     if(!chflag && rflag) {
  658.         printf("Input file? ");
  659.         gets(rname);
  660.         if(!strlen(rname) || opento())
  661.             return(0);
  662.         }
  663.     hd_sav=hdflag;
  664.     hdflag = 0;
  665.     return(ask("\nOK...type y to begin, n to abort:"));
  666. }
  667.  
  668. /*
  669.     Routine to print out a string and return true
  670.     if the user responds positively
  671. */
  672.  
  673. ask(s)
  674. char    *s;
  675. {
  676.     char    c;
  677.  
  678.     while (1) {
  679.         printf("%s (y/n)? ",s);
  680.         switch(c=toupper(getchar())) {
  681.             case 'Y':    printf("es\n");    
  682.             case '1' :    return 1;
  683.  
  684.             case 'N' :    printf("o\n");
  685.             case '0' :
  686.             case NL :    return 0;
  687.  
  688.             default :    printf("???\n");
  689.                     break;
  690.             }
  691.         }
  692. }
  693.  
  694.  
  695. /*
  696.     Print out status of Telnet
  697. */
  698.  
  699. dostat()
  700. {
  701.     putchar(NL);
  702.     if (rflag) {
  703.         printf("Output file = %s\n",rname);
  704.         printf("\nText collection: ");
  705.             if (cflag)
  706.                 if (pflag) printf("on, but pausing\n");
  707.                 else printf("on\n");
  708.             else printf("off\n");
  709.         }
  710.     else printf("No output file\n");
  711.     printf("Text buffer has %u bytes free\n",free);
  712.     if (tflag) {
  713.         printf("Transmitting: %s ",tname);
  714.         if (pflag)
  715.             printf("(but pausing)");
  716.         putchar(NL);
  717.         }
  718.     else printf("Not transmitting any file\n");
  719.     printf("Current Escape Character: 0x%02x\n",SPECIAL);
  720.     printf("Incoming nulls are being %s\n",nflag?"collected" : "ignored");
  721.     printf("Parity bits are being %s\n",spflag ?"stripped" : "preserved");
  722.     printf("%s\n",hdflag ? "Half-Duplex" : "Full-Duplex");
  723.     printf("Current Baud rates: Main: %s  Aux: %s\n",
  724.             bauds[current&0xf],bauds[current>>4]);
  725.     printf("Disk: %c:\n",disk());
  726. }
  727.  
  728.  
  729. /*
  730.     Routine to dump contents of the memory text buffer
  731.     to the output file and clear the buffer for more
  732.     data:
  733. */
  734.  
  735. rdump(n)
  736. {
  737.     for (i=buf; i<cptr; i++)
  738.         putc(*i,rbuf);
  739.     cptr = buf;
  740.     free = bufspace;
  741.     if (n)
  742.         printf("\nBuffer written. ");
  743. }
  744.  
  745.  
  746. /*
  747.     Routine to dump and close the output file:
  748. */
  749.  
  750. rclose()
  751. {
  752.     rdump(1);
  753.     printf(" Closing %s ",rname);
  754.     if (!chflag)
  755.         putc(CPMEOF,rbuf);
  756.     fflush(rbuf);
  757.     close(rfd);
  758.     putchar(NL);
  759. }
  760.  
  761. /*
  762.     Routine to reset telnet
  763. */
  764.  
  765. reset()
  766. {
  767.     leftover = scount = timoutf = rflag = tflag = chflag = cflag = 0;
  768.     didflag = spflag = 1;
  769.     dodflag = !hdflag;
  770.     hdflag=hd_sav;
  771. }
  772.  
  773.  
  774. /*
  775.     Get a byte from the modem:
  776. */
  777.  
  778. getmod()
  779. {
  780.     char    c;
  781.     unsigned n;
  782.  
  783.     if (timoutf) 
  784.         return;
  785.     for (n=20000; !miready() && n; n--)
  786.         if (kbabort()) 
  787.             return;
  788.     if (!n) {
  789.         timoutf = 1;
  790.         return(1);
  791.         }
  792.     c = mgetc();
  793.     return(c);
  794. }
  795.  
  796.  
  797. /*
  798.     Output a byte to the modem:
  799. */
  800.  
  801. outmod(c)
  802. char c;
  803. {
  804.     while (!moready())
  805.         if (kbabort())
  806.             return;
  807.     mputc(c);
  808. }
  809.  
  810. /*
  811.     return true if a key has been pressed, else 0
  812. */
  813.  
  814. kbready()
  815. {
  816.     return bios(2);
  817. }
  818.  
  819. /*
  820.     Get a character from the keyboard:
  821.     (Uses a direct BIOS instead of going through
  822.     the BDOS. By naming this the same as the library
  823.     version of "getchar", we insure that THIS version
  824.     is used by things like "gets" instead of the library
  825.     version.)
  826. */
  827.  
  828. getchar()
  829. {
  830.     char c;
  831.  
  832.     c = getch();
  833.     if (c == CR)
  834.         c = NL;
  835.     putchar(c);
  836.     return c;
  837. }
  838.  
  839. getch()
  840. {
  841.     return bios(3);
  842. }
  843.  
  844.  
  845. /*
  846.     Return true if keyboard hit and SPECIAL typed:
  847. */
  848.  
  849. kbabort()
  850. {
  851.     if (kbready() && getch() == SPECIAL) {
  852.         abortf = 1;
  853.         return 1;
  854.         }
  855.     return 0;
  856. }
  857.  
  858.  
  859. /*
  860.     Write a character to the console.
  861. */
  862.  
  863. putchar(c)
  864. char c;
  865. {
  866.     if (c == NL)
  867.         putch2(CR);
  868.     putch2(c);
  869. }
  870.  
  871. putch2(c)
  872. char c;
  873. {
  874.     bios(4,c);
  875. }
  876.  
  877.  
  878. /*
  879.     Write character to console display
  880. */
  881.  
  882. display(c)
  883. char c;
  884. {
  885.     putch2(c&0x7f);
  886. }
  887.  
  888.  
  889.  
  890. /*
  891.     Read a sector of the transmission file:
  892. */
  893.  
  894. read1()
  895. {
  896.     int i;
  897.  
  898.     i = read(tfd, tbuf, 1);
  899.     if ( i == ERROR) {
  900.         printf("\nRead error from %s; Aborting.\n",tname);
  901.         tabort();
  902.         }    
  903.     return(i);
  904. }
  905.  
  906. tabort()
  907. {
  908.     if (chflag)
  909.         while (bcount++ != 133)
  910.             outmod(ETX);
  911.     printf("\nTransmission of %s aborted.\n",tname);
  912.      close(tfd);
  913.     reset();
  914. }
  915.  
  916. /*
  917.     create receiving file. if it already exists, change type name
  918.     and try again.
  919. */
  920.  
  921. opento()    
  922. {
  923.     char    c;
  924.  
  925.     c=1;
  926.     printf("Creating %s...",rname);
  927.     while((rfd=open(rname,0)) != ERROR) {
  928.         close(rfd);
  929.         addtype(rname,c++);
  930.         printf("File exists..Trying %s...",rname);
  931.         }
  932.     if ((rfd=fcreat(rname,rbuf)) == ERROR) {
  933.         printf("Cannot create %s\n",rname);
  934.         reset();
  935.         return(1);
  936.         }
  937.     return(0);
  938. }
  939.  
  940. /*
  941.     add sub name to file name if file already exsists
  942. */
  943.  
  944. addtype(f,c)
  945. char    *f,c;
  946. {
  947.     char    d,o[4];
  948.  
  949.     for(d=0;f[d] && f[d]!='.';d++);
  950.     sprintf(o,"%-3d",c);
  951.     if(!f[d]) {
  952.         f[d]='.';
  953.         f[d+1]=0;
  954.         }
  955.     else
  956.         f[d+1]=0;
  957.     strcat(f,o);
  958. }
  959.  
  960. /*
  961.     send file name being transmitted
  962. */
  963.  
  964. sendname(f)
  965. char    *f;
  966. {
  967.     char    c;
  968.  
  969.     for(c=0; *f && c<12; c++)
  970.         outmod(*(f++));
  971.     outmod(NUL);
  972. }
  973.  
  974. /*
  975.     get file name being sent
  976. */
  977.  
  978. getname(a)
  979. char    *a;
  980. {
  981.     char    d,c,*q;
  982.  
  983.     q=a;
  984.     for(d=0; (c=getmod()) && d<12; d++)
  985.         *(q++)=c;
  986.     *q=0;
  987. }
  988.  
  989. /*
  990.     display files on currently logged in disk
  991. */
  992.  
  993. dir()
  994. {
  995.     char    f;
  996.     struct    FCB    fcb;
  997.  
  998.     putchar(NL);
  999.     bdos(SELDSK,thisdisk&0x0f);
  1000.     strcpy(files[0],"????????.???");
  1001.     leftover=1;
  1002.     nameok();
  1003.     for(f=0;f<leftover;f++)
  1004.         printf("%-12s%c",files[f],((f+1)%6)?' ':'\n');
  1005.     putchar(NL);
  1006. }
  1007.  
  1008. /* 
  1009.     returns disk name of currently logged in disk
  1010. */
  1011.  
  1012. disk()
  1013. {
  1014.     return("AB"[bdos(CURRDSK,0)&0x0f]);
  1015. }
  1016.  
  1017. /* 
  1018.     change currently logged-in disk to other disk
  1019. */
  1020.  
  1021. togdisk()
  1022. {
  1023.     bdos(SELDSK,(thisdisk=((thisdisk)?0:1)));
  1024.     return(disk());
  1025. }
  1026.  
  1027. /*
  1028.     check to see if this file is in directory
  1029. */
  1030.  
  1031. nameok()
  1032. {
  1033.     char    f,c,o[20];
  1034.     struct    FCB    fcb;
  1035.  
  1036.     if(!strlen(files[leftover-1])) 
  1037.         return(1);
  1038.     setfcb(fcb,files[leftover-1]);
  1039.     leftover--;
  1040.     for(f=DIRFRST;(c=bdos(f,&fcb))!=255 && leftover<maxfiles;f=DIRNEXT) {
  1041.         pickout(0x80+(c*32),o);
  1042.         strcpy(files[leftover++],o);
  1043.         }
  1044.     return((leftover<maxfiles)?0:1);
  1045. }
  1046.  
  1047.  
  1048. xmit()
  1049. {
  1050.     int incheck;
  1051.     int n;
  1052.     char c;
  1053.  
  1054.     if (pflag || !moready())
  1055.         return 0;
  1056.     c = tbuf[bcount++];
  1057.     checksum += c;
  1058.     if ((!(spflag && (c&0x7f)==CPMEOF && !chflag)) &&
  1059.         (!(!chflag && c==NL && lastc==CR && !nflag && fflag)))
  1060.             outmod(c);
  1061.     lastc = c;
  1062.     if (dodflag)
  1063.         display(c);
  1064.     if (bcount != SECSIZ)
  1065.         return 0;
  1066.     bcount = 0;
  1067.     if (!chflag)
  1068.         return(!read1());
  1069.     incheck = (getmod() << 8) + getmod();
  1070.     if (incheck != checksum) {
  1071.         for (n=0; n<20000; n++);     /* let line settle down */
  1072.         printf("\nError. Resending sector %d...\n",scount+1);
  1073.         outmod(NAK);
  1074.         }
  1075.     else if (read1()) {
  1076.         if (!dodflag) 
  1077.             printf(".%d",++scount);
  1078.         outmod(ACK);
  1079.         }
  1080.     else if(leftover) {
  1081.         close(tfd);
  1082.         --leftover;
  1083.         strcpy(tname,files[leftover-1]);
  1084.         while(leftover && ((tfd=open(tname,0))==ERROR)){
  1085.             if(!dodflag)
  1086.                 printf("Unknown error: Can't open %s\n",tname);
  1087.             leftover=0;
  1088.             }
  1089.         if (!leftover) {
  1090.             reset();
  1091.             putchar(NL);
  1092.             outmod(EOT); 
  1093.             return(1);
  1094.             }
  1095.         if(!dodflag)
  1096.             printf("\nSending %d: %s\n",leftover,tname);
  1097.         outmod(STX);
  1098.         sendname(tname);
  1099.         scount = pflag = checksum = bcount = 0;
  1100.         if (read(tfd,tbuf,1) <=0) {
  1101.             printf("Read error from %s\n",tname);
  1102.             reset();
  1103.             abortf = 1;
  1104.             return;
  1105.             }
  1106.         }
  1107.         else { 
  1108.         outmod(EOT); 
  1109.         return(1);
  1110.         }
  1111.     checksum = 0;
  1112.     if (getmod() != PHA) {
  1113.         printf("\nPhase error; aborting...");
  1114.         abortf = 1;
  1115.         }
  1116.     return 0;
  1117. }
  1118.